import 'dart:math';

import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';

class SelfWidgetTest extends StatefulWidget {
  @override
  State<StatefulWidget> createState() {
    // TODO: implement createState
    return _SelfWidgetTestState();
  }
}

class _SelfWidgetTestState extends State<SelfWidgetTest>
    with SingleTickerProviderStateMixin {
  double _turn = 0.0;
  Offset _offset;
  var _value = 0.0;
  var _oldValue = 0.0;
  AnimationController _controller;
  Animation _animation;

  @override
  void initState() {
    // TODO: implement initState
    super.initState();
    _controller =
        AnimationController(vsync: this, duration: Duration(seconds: 2));
    _animation = CurvedAnimation(parent: _controller, curve: Curves.bounceIn);
    //_animation = Tween(begin: 0.0,end: 1.0).animate(_animation);
    _animation.addListener(() {
      setState(() {});
    });
    _controller.forward();
  }

  @override
  Widget build(BuildContext context) {
    // TODO: implement build
    return Scaffold(
      appBar: AppBar(
        title: Text("自定义组合组件"),
      ),
      body: Center(
        child: Column(
          children: <Widget>[
            GradientButton(
              width: 150,
              height: 50,
              child: Text('自定义按钮1'),
              colors: [Colors.red, Colors.pink],
              borderRadius: BorderRadius.all(Radius.circular(10.0)),
              callback: () {},
            ),
            GestureDetector(
              onTap: () {
                setState(() {
                  _turn += 0.25;
                  _oldValue = _value;
                  _value = _turn;
                });
              },
              child: TurnBox(
                turn: _turn,
                speed: 300,
                child: Padding(
                  padding: EdgeInsets.all(20),
                  child: Icon(
                    Icons.refresh,
                    size: 50,
                  ),
                ),
              ),
            ),
            GestureDetector(
              onPanDown: (detail) {
                setState(() {
                  _offset = detail.localPosition;
                });
              },
              child: CustomPaint(
                painter: MyPainterPan(),
                size: Size(200, 200),
                child: RepaintBoundary(
                    child: CustomPaint(
                  painter: MyPainter(offset: _offset),
                  size: Size(200, 200),
                )),
              ),
            ),
            GradientCircularProgressIndicator(
              // No gradient
              colors: [Colors.purple, Colors.red],
              backgroundColor: Colors.greenAccent,
              radius: 100,
              strokeCapRound: true,
              strokeWidth: 10.0,
              value: _animation.value,
            ),
          ],
        ),
      ),
    );
  }
}

class GradientCircularProgressIndicator extends StatelessWidget {
  GradientCircularProgressIndicator(
      {this.strokeWidth = 2.0,
      @required this.radius,
      @required this.colors,
      this.stops,
      this.strokeCapRound = false,
      this.backgroundColor = const Color(0xFFEEEEEE),
      this.totalAngle = 2 * pi,
      this.value});

  ///粗细
  final double strokeWidth;

  /// 圆的半径
  final double radius;

  ///两端是否为圆角
  final bool strokeCapRound;

  /// 当前进度，取值范围 [0.0-1.0]
  final double value;

  /// 进度条背景色
  final Color backgroundColor;

  /// 进度条的总弧度，2*PI为整圆，小于2*PI则不是整圆
  final double totalAngle;

  /// 渐变色数组
  final List<Color> colors;

  /// 渐变色的终止点，对应colors属性
  final List<double> stops;

  @override
  Widget build(BuildContext context) {
    double _offset = 0.0;
    // 如果两端为圆角，则需要对起始位置进行调整，否则圆角部分会偏离起始位置
    // 下面调整的角度的计算公式是通过数学几何知识得出
    if (strokeCapRound) {
      _offset = asin(strokeWidth / (radius * 2 - strokeWidth));
    }
    var _color = colors;
    if (_color == null) {
      Color color = Theme.of(context).accentColor;
      _color = [color, color];
    }
    // TODO: implement build
    return Transform.rotate(
      angle: -pi / 2.0 - _offset,
      child: CustomPaint(
        size: Size.fromRadius(radius),
        painter: _GradientCircularProgressPainter(
            colors: _color,
            radius: radius,
            totalAngle: totalAngle,
            value: value,
            backgroundColor: backgroundColor,
            strokeCapRound: strokeCapRound,
            strokeWidth: strokeWidth),
      ),
    );
  }
}

class _GradientCircularProgressPainter extends CustomPainter {
  _GradientCircularProgressPainter(
      {this.strokeWidth = 10.0,
      this.strokeCapRound = false,
      this.backgroundColor = const Color(0xFFEEEEEE),
      @required this.colors,
      this.radius,
      this.totalAngle = 2 * pi,
      this.value,
      this.stops});

  ///粗细
  final double strokeWidth;

  /// 圆的半径
  final double radius;

  ///两端是否为圆角
  final bool strokeCapRound;

  /// 当前进度，取值范围 [0.0-1.0]
  final double value;

  /// 进度条背景色
  final Color backgroundColor;

  /// 进度条的总弧度，2*PI为整圆，小于2*PI则不是整圆
  final double totalAngle;

  /// 渐变色数组
  final List<Color> colors;

  /// 渐变色的终止点，对应colors属性
  final List<double> stops;

  @override
  void paint(Canvas canvas, Size size) {
    // TODO: implement paint
    if (radius != null) {
      size = Size.fromRadius(radius);
    }
    double _offset = strokeWidth / 2.0;
    double _value = value ?? 0.0;
    _value = _value.clamp(0.0, 1.0) * totalAngle;
    double _start = 0.0;
    if (strokeCapRound) {
      _offset = asin(strokeWidth / (radius * 2 - strokeWidth));
    }

    Rect rect = Offset(_offset, _offset) &
        Size(size.width - strokeWidth, size.height - strokeWidth);

    var paint = Paint()
      ..strokeWidth = strokeWidth
      ..style = PaintingStyle.stroke
      ..isAntiAlias = true
      ..strokeCap = strokeCapRound ? StrokeCap.round : StrokeCap.butt;

    //背景
    if (backgroundColor != Colors.transparent) {
      paint.color = backgroundColor;
      canvas.drawArc(rect, _start, totalAngle, false, paint);
    }
    //前景
    if (_value > 0) {
      paint.shader =
          SweepGradient(colors: colors, startAngle: 0.0, endAngle: _value, stops: stops)
              .createShader(rect);

      canvas.drawArc(rect, _start, _value, false, paint);
    }
  }

  @override
  bool shouldRepaint(CustomPainter oldDelegate) {
    // TODO: implement shouldRepaint
    return true;
  }
}

class MyPainter extends CustomPainter {
  MyPainter({this.offset});

  final Offset offset;
  var _spWidth;
  var _spHeight;

  @override
  void paint(Canvas canvas, Size size) {
    // TODO: implement paint
    _spWidth = size.width / 15;
    _spHeight = size.height / 15;
    var paint = Paint()
      ..style = PaintingStyle.fill
      ..color = Colors.black;

    if (offset != null) {
      canvas.drawCircle(getOffset(offset), _spWidth / 2, paint);
    }
  }

  Offset getOffset(Offset point) {
    int dxx = point.dx ~/ _spWidth;
    int dxx2 = dxx + 1;
    int dx;
    if ((dxx2 * _spWidth - point.dx).abs() <
        (dxx * _spWidth - point.dx).abs()) {
      dx = dxx2;
    } else {
      dx = dxx;
    }
    int dyy = point.dy ~/ _spHeight;
    int dyy2 = dyy + 1;
    int dy;
    if ((dyy2 * _spHeight - point.dy).abs() <
        (dyy * _spHeight - point.dy).abs()) {
      dy = dyy2;
    } else {
      dy = dyy;
    }

    return Offset(dx * _spWidth, dy * _spHeight);
  }

  @override
  bool shouldRepaint(CustomPainter oldDelegate) {
    // TODO: implement shouldRepaint
    return true;
  }
}

class MyPainterPan extends CustomPainter {
  @override
  void paint(Canvas canvas, Size size) {
    var spWidth = size.width / 15;
    var spHeight = size.height / 15;
    // TODO: implement paint
    var paint = Paint()
      ..isAntiAlias = true
      ..style = PaintingStyle.fill
      ..color = Color(0x77cdb175);
    canvas.drawRect(Offset.zero & size, paint);

    paint = Paint()
      ..style = PaintingStyle.stroke
      ..color = Colors.black
      ..strokeWidth = 1.0;

    for (int i = 0; i <= 15; i++) {
      canvas.drawLine(
          Offset(0, i * spHeight), Offset(size.width, i * spHeight), paint);

      canvas.drawLine(
          Offset(i * spWidth, 0), Offset(i * spWidth, size.height), paint);
    }
  }

  @override
  bool shouldRepaint(CustomPainter oldDelegate) {
    // TODO: implement shouldRepaint
    return false;
  }
}

class GradientButton extends StatelessWidget {
  GradientButton(
      {this.colors,
      this.width,
      this.height,
      this.borderRadius,
      this.callback,
      @required this.child});

  //按钮的颜色list
  final List<Color> colors;

  //按钮的宽高
  final double width;
  final double height;
  final Widget child;
  final BorderRadius borderRadius;
  final GestureTapCallback callback;

  @override
  Widget build(BuildContext context) {
    ThemeData themeData = Theme.of(context);
    //确保colors数组不空
    List<Color> _colors = colors ??
        [
          themeData.primaryColor,
          themeData.primaryColorDark ?? themeData.primaryColor
        ];
    // TODO: implement build
    return DecoratedBox(
        decoration: BoxDecoration(
            gradient: LinearGradient(colors: _colors),
            borderRadius: borderRadius),
        child: Material(
          type: MaterialType.transparency,
          child: InkWell(
              splashColor: _colors.last,
              highlightColor: Colors.transparent,
              borderRadius: borderRadius,
              onTap: callback,
              child: SizedBox(
                width: width,
                height: height,
                child: Center(child: child),
              )),
        ));
  }
}

class TurnBox extends StatefulWidget {
  TurnBox({Key key, this.turn, this.speed, this.child}) : super(key: key);
  final double turn;
  final int speed;
  final Widget child;

  @override
  State<StatefulWidget> createState() {
    // TODO: implement createState
    return _TurnBoxState();
  }
}

class _TurnBoxState extends State<TurnBox> with TickerProviderStateMixin {
  AnimationController _controller;
  Animation _animation;

  @override
  void initState() {
    // TODO: implement initState
    super.initState();
    _controller = AnimationController(
      vsync: this,
      duration: Duration(milliseconds: 200),
    );
  }

  @override
  void dispose() {
    // TODO: implement dispose
    super.dispose();
    _controller.dispose();
  }

  @override
  Widget build(BuildContext context) {
    if (_animation == null) {
      _animation = Tween(begin: 0.0, end: 0.0).animate(_controller);
    }
    // TODO: implement build
    return RotationTransition(
      turns: _animation,
      child: widget.child,
    );
  }

  @override
  void didUpdateWidget(TurnBox oldWidget) {
    // TODO: implement didUpdateWidget
    super.didUpdateWidget(oldWidget);

    if (oldWidget.turn != widget.turn) {
      _controller = AnimationController(
        vsync: this,
        duration: Duration(milliseconds: 200),
      );
      _animation =
          Tween(begin: oldWidget.turn, end: widget.turn).animate(_controller);
      _controller.forward();

      //另一种方法
//      _controller.animateTo(
//        widget.turn,
//        duration: Duration(milliseconds: widget.speed??200),
//      );
    }
  }
}
